package com.itdct.onflow.core.util;


import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.Charset;

import javax.imageio.ImageIO;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.MD5;

/**
 * @author DCTANT
 * @version 1.0
 * @date 2023/4/28 15:55:23
 * @description 用于生成文件MD5图片的方法
 */
public class GenerateMd5Pic {
    private MD5 md5 = new MD5();
    /**
     * 每个格子占据的像素大小
     */
    private int blockSize = 200;
    /**
     * 内边距，默认为两倍的格子宽度
     */
    private int padding = 400;
    /**
     * 背景颜色，默认为白色
     */
    private Color backgroundColor = new Color(255, 255, 255);
    /**
     * 输出路径
     */
    private String outputPath;
    /**
     * 输入文件路径
     */
    private String filePath;
    /**
     * 是否输出md5文件
     */
    private boolean writeMd5File;
    /**
     * 输入文件的文件名
     */
    private String fileName;
    /**
     * 是否打印md5图像在控制台
     */
    private boolean printBlock;

    /**
     * 通过32位长度的字符串生成图片
     *
     * @param hexString
     */
    public void string32Img(String hexString) {
        if (hexString.length() != 32) {
            throw new RuntimeException("输入字符串参数长度不是32");
        }

        // INFO: DCTANT: 2023/4/28 取RGB的总值
        String redTotal = hexString.substring(0, 10);
        String greenTotal = hexString.substring(10, 20);
        String blueTotal = hexString.substring(20, 32);

        // INFO: DCTANT: 2023/4/28 获取到平均后的rgb的值
        int r = getAverage256Value(redTotal);
        int g = getAverage256Value(greenTotal);
        int b = getAverage256Value(blueTotal);
        // INFO: DCTANT: 2023/4/28 定义每个格子的颜色
        Color blockColor = new Color(r, g, b);

        // INFO: DCTANT: 2023/4/28 计算图片的总像素宽度
        int picSize = 2 * padding + blockSize * 16;

        BufferedImage bufferedImage = new BufferedImage(picSize, picSize, BufferedImage.TYPE_INT_RGB);

        // INFO: DCTANT: 2023/4/28 获取图片画笔
        Graphics2D graphics2D = (Graphics2D) bufferedImage.getGraphics();
        // INFO: DCTANT: 2023/4/28 设置背景颜色
        graphics2D.setColor(backgroundColor);
        // INFO: DCTANT: 2023/4/28 画出整个背景
        graphics2D.fillRect(0, 0, picSize, picSize);

        boolean[][] blockArray = calculateBlockArray(hexString);

        graphics2D.setColor(blockColor);
        // INFO: DCTANT: 2023/4/28 绘制每个格子
        for (int column = 0; column < blockArray.length; column++) {
            boolean[] rows = blockArray[column];
            for (int row = 0; row < rows.length; row++) {
                boolean isBlock = rows[row];
                if (!isBlock) {
                    continue;
                }
                // INFO: DCTANT: 2023/4/28 数值为1的，画出方格
                int x = padding + column * blockSize;
                int y = padding + row * blockSize;
                graphics2D.fillRect(x, y, blockSize, blockSize);
            }
        }

        if (printBlock) {
            for (int row = 0; row < 16; row++) {
                // INFO: DCT: 2023/5/5 一共16行
                for (int column = 0; column < blockArray.length; column++) {
                    boolean isBlock = blockArray[column][row];
                    if (isBlock) {
                        System.out.print("■");
                    } else {
                        System.out.print("　");
                    }
                }
                System.out.println();
            }
        }

        String finalFilePath = "";
        if (StrUtil.isBlank(outputPath)) {
            if (StrUtil.isBlank(filePath)) {
                finalFilePath = "./" + hexString + ".jpg";
            } else {
                finalFilePath = filePath + ".md5.jpg";
            }
        } else {
            // INFO: DCT: 2023/5/5 存在指定输出md5路径
            if (!outputPath.endsWith("/")) {
                outputPath = outputPath + "/";
            }
            if (StrUtil.isNotBlank(filePath)) {
                outputPath = outputPath.replaceAll("\\\\", "/");
                filePath = filePath.replaceAll("\\\\", "/");
                // INFO: DCT: 2023/5/5 说明是文件输出
                int lastIndexOf = filePath.lastIndexOf("/");
                if (lastIndexOf == -1) {
                    fileName = filePath;
                } else {
                    fileName = filePath.substring(lastIndexOf + 1);
                }
                finalFilePath = outputPath + fileName + ".md5.jpg";
            } else {
                // INFO: DCT: 2023/5/5 字符串输出
                finalFilePath = outputPath + hexString + ".jpg";
            }
        }

        try {
            File file = new File(finalFilePath);
            System.out.println("输出路径为：" + file.getAbsolutePath());
            ImageIO.write(bufferedImage, "JPG", new FileOutputStream(finalFilePath));//保存图片 JPEG表示保存格式
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 通过十六进制字符串，计算出16*16的像素数组
     *
     * @param hexString
     * @return
     */
    private boolean[][] calculateBlockArray(String hexString) {
        boolean[][] blockArray = new boolean[16][16];
        for (int column = 0; column < 8; column++) {
            // INFO: DCTANT: 2023/4/28 将32位的md5，每4位切一个下来
            String fourHexString = hexString.substring(column * 4, (column + 1) * 4);
            // INFO: DCTANT: 2023/4/28 转为十进制
            int decimal = HexUtil.hexToInt(fourHexString);
            // INFO: DCTANT: 2023/4/28 十进制转二进制
            StringBuilder binaryBuilder = new StringBuilder(Integer.toBinaryString(decimal));
            // INFO: DCTANT: 2023/4/28 补零
            if (binaryBuilder.length() < 16) {
                int addZeroCount = 16 - binaryBuilder.length();
                for (int i = 0; i < addZeroCount; i++) {
                    binaryBuilder.insert(0, "0");
                }
            }

            // INFO: DCTANT: 2023/4/28 转为字符数组，用于判断是0还是1
            char[] chars = binaryBuilder.toString().toCharArray();
            for (int row = 0; row < chars.length; row++) {
                char theOneOrZero = chars[row];
                if (theOneOrZero == '1') {
                    blockArray[column][row] = true;
                    // INFO: DCTANT: 2023/4/28 对称点赋值
                    blockArray[15 - column][row] = true;
                } else {
                    blockArray[column][row] = false;
                    // INFO: DCTANT: 2023/4/28 对称点赋值
                    blockArray[15 - column][row] = false;
                }
            }
        }
        return blockArray;
    }

    /**
     * 通过文件生成其MD5图像
     *
     * @param filePath
     */
    public void fileImg(String filePath) {
        File file = new File(filePath);
        if (!file.exists()) {
            throw new RuntimeException("文件不存在");
        }

        String md5String = md5.digestHex(filePath);
        System.out.println("file md5 is " + md5String);
        this.filePath = filePath;
        string32Img(md5String);

        if (writeMd5File) {
            if (StrUtil.isNotBlank(outputPath)) {
                // INFO: DCT: 2023/5/5 有指定输出目录
                FileUtil.writeString(md5String, outputPath + fileName + ".md5", Charset.defaultCharset());
            } else {
                FileUtil.writeString(md5String, filePath + ".md5", Charset.defaultCharset());
            }
        }

    }

    /**
     * 计算整个十六进制字符串的其中两位的平均值，并四舍五入
     *
     * @param hex 该十六进制字符串每两位的平均值
     * @return
     */
    public int getAverage256Value(String hex) {
        int loopCount = hex.length() / 2;
        if (hex.length() % 2 == 1) {
            throw new RuntimeException("hex长度必须为偶数");
        }
        double total = 0.0;
        for (int i = 0; i < loopCount; i++) {
            String twoHex = hex.substring(i * 2, (i + 1) * 2);
            int value = HexUtil.hexToInt(twoHex);
            total += value;
        }
        double value = total / loopCount;
        int result = new BigDecimal(value).setScale(0, RoundingMode.HALF_UP).intValue();
        return result;

    }

    public static void main(String[] args) {
        GenerateMd5Pic generateMd5Pic = new GenerateMd5Pic().setWriteMd5File(true);
        generateMd5Pic.fileImg("C:\\Tmp\\test\\jenkins.war");
    }

    public String getFilePath() {
        return filePath;
    }

    public GenerateMd5Pic setFilePath(String filePath) {
        this.filePath = filePath;
        return this;
    }

    public int getBlockSize() {
        return blockSize;
    }

    public GenerateMd5Pic setBlockSize(int blockSize) {
        this.blockSize = blockSize;
        return this;
    }

    public int getPadding() {
        return padding;
    }

    public GenerateMd5Pic setPadding(int padding) {
        this.padding = padding;
        return this;
    }

    public String getOutputPath() {
        return outputPath;
    }

    public GenerateMd5Pic setOutputPath(String outputPath) {
        this.outputPath = outputPath;
        return this;
    }

    public GenerateMd5Pic setBackgroundColor(Color backgroundColor) {
        this.backgroundColor = backgroundColor;
        return this;
    }

    public boolean isWriteMd5File() {
        return writeMd5File;
    }

    public GenerateMd5Pic setWriteMd5File(boolean writeMd5File) {
        this.writeMd5File = writeMd5File;
        return this;
    }

    public boolean isPrintBlock() {
        return printBlock;
    }

    public GenerateMd5Pic setPrintBlock(boolean printBlock) {
        this.printBlock = printBlock;
        return this;
    }
}
